#!/usr/bin/env bash
# Copyright (c) 2024 maminjie <canpool@163.com>
# SPDX-License-Identifier: MulanPSL-2.0

CUR_DIR=$(pwd)
WORK_DIR="$CUR_DIR/oe_make_rootfs_workspace"
ROOTFS_DIR="$WORK_DIR/rootfs"

IN_FILE=""
OUT_FILE=""
OUT_DIR=""
TYPE="ext4"

TYPES="ext4"

usage() {
printf "make rootfs image based on openEuler embedded rootfs.cpio.gz

usage:
    bash oe_make_rootfs.sh [-h] [-i INFILE] [-o OUTFILE] [-d OUTDIR] [-t TYPE]

optional arguments:
    -i INFILE      openEuler embedded xxx.rootfs.cpio.gz
    -o OUTFILE     output image file, default is xxx.rootfs.TYPE.img in current dir
    -d OUTDIR      output directory, default is current dir
    -t TYPE        image type, default is ext4, includes:
                       ${TYPES}
    -h             show the help message and exit
\n"
}

check_type() {
    for typename in $TYPES; do
        if [ "${typename}" = "${TYPE}" ]; then
            return 0
        fi
    done

    return 1
}

log_error() {
    echo "ERROR: $1"
}

parse_cmdline() {
    if [ $# -eq 0 ]; then
        usage; exit 0
    fi
    # parse cmd line arguments
    while getopts ":i:o:d:t:h" opt; do
        case "$opt" in
            i)
                if [ -f "$OPTARG" ]; then
                    IN_FILE="$OPTARG"
                fi
            ;;
            o)
                OUT_FILE="$OPTARG"
            ;;
            d)
                OUTDIR="$OPTARG"
            ;;
            t)
                TYPE="$OPTARG"
            ;;
            h)
                usage; exit 0
            ;;
            ?)
                log_error "please check the params."; usage; return 1
            ;;
        esac
    done

    if [ ! -f "$IN_FILE" ]; then
        log_error "no such file $IN_FILE"; return 1
    fi
    if [[ ! "$IN_FILE" =~ \.cpio\.gz$ ]]; then
        log_error "file $IN_FILE suffix is not .cpio.gz"; return 1
    fi

    if [ -z "$OUT_DIR" ]; then
        OUT_DIR="$CUR_DIR"
    fi

    check_type
    if [ $? -ne 0 ]; then
        log_error "unsupported type: $TYPE"; return 1
    fi

    if [ -z "$OUT_FILE" ]; then
        local in_file_name=${IN_FILE##*/}
        in_file_name=${in_file_name%.cpio.gz}
        OUT_FILE=$in_file_name.$TYPE.img
    else
        OUT_FILE=${OUT_FILE##*/}
    fi

    return 0
}

check_user() {
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root!"
        exit 1
    fi
}

check_requires() {
    local ret=0

    for c in cpio zcat mkfs.ext4; do
        command -v $c > /dev/null
        if [ $? -ne 0 ]; then
            log_error "command $c not found"
            ret=1
        fi
    done

    return $ret
}

clean() {
    cd "$CUR_DIR" || exit
    [[ -d "${WORK_DIR}" ]] && rm -rf "${WORK_DIR}"
}

do_main() {
    clean

    mkdir -p $WORK_DIR
    mkdir -p $ROOTFS_DIR
    mkdir -p $OUT_DIR

    # uncompress
    zcat $IN_FILE | cpio -idm -D $ROOTFS_DIR

    local size=$(du -sh --block-size=1MiB ${ROOTFS_DIR} | cut -f 1 | xargs)
    size=$(($size+500))
    local rootfs_img=${OUT_DIR}/${OUT_FILE}
    dd if=/dev/zero of=${rootfs_img} bs=1MiB count=$size status=progress && sync
    if [ "$TYPE" = "ext4" ]; then
        mkfs.ext4 ${rootfs_img}
    else
        mkfs.ext4 ${rootfs_img}
    fi

    local rootfs_tmpdir=${WORK_DIR}/rootfs_tmp
    if [ -d ${rootfs_tmpdir} ]; then
        rm -rf ${rootfs_tmpdir}
    fi
    mkdir ${rootfs_tmpdir}
    mount ${rootfs_img} ${rootfs_tmpdir}

    cp -a ${ROOTFS_DIR}/* ${rootfs_tmpdir}
    sync

    umount ${rootfs_tmpdir} 2> /dev/null

    if [ ! -f $rootfs_img ]; then
        return 1
    fi
    echo "outfile: $rootfs_img"

    clean

    return 0
}

main() {
    check_user

    parse_cmdline "$@"
    if [ $? -ne 0 ]; then
        log_error "parse params failed, try -h for help"
        return 1
    fi

    check_requires
    if [ $? -ne 0 ]; then
        log_error "check requires failed"
        return 1
    fi

    do_main
    if [ $? -ne 0 ]; then
        return 1
    fi

    return 0
}

main "$@"
